﻿using Irony.Interpreter;
using Irony.Interpreter.Ast;
using Irony.Parsing;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AppServidor
{
    
    class GramaticaPista: Grammar
    {
        public GramaticaPista()
            : base(caseSensitive: true)
        {
            StringLiteral cad = TerminalFactory.CreateCSharpString("cad");
            StringLiteral caracter = TerminalFactory.CreateCSharpChar("caracter");
            NumberLiteral num = TerminalFactory.CreateCSharpNumber("num");
            IdentifierTerminal id = TerminalFactory.CreateCSharpIdentifier("id");

            CommentTerminal SingleLineComment = new CommentTerminal("SingleLineComment", ">>", "\n", "\r\n");
            CommentTerminal DelimitedComment = new CommentTerminal("DelimitedComment", "<_", "_>");
            base.NonGrammarTerminals.Add(SingleLineComment);
            base.NonGrammarTerminals.Add(DelimitedComment);

            KeyTerm Lpar = ToTerm("(");
            KeyTerm Rpar = ToTerm(")");

            CommentTerminal escape = new CommentTerminal("escape", "\r\n");
            // RegexBasedTerminal cade = new RegexBasedTerminal("cade", "([0-9]*([a-z]|[A-Z])+[0-9]*)+");
            //   RegexBasedTerminal num = new RegexBasedTerminal("Number", "[0-9]+");
            base.NonGrammarTerminals.Add(escape);

            NonTerminal S = new NonTerminal("s"),
                        P = new NonTerminal("P"),
                        NM = new NonTerminal("NM"),
                        NPista = new NonTerminal("NPista"),
                        CPista = new NonTerminal("CPista"),
                        CallMorF = new NonTerminal("CallMorF"),
                        Param = new NonTerminal("Param"),
                        Tipo = new NonTerminal("Tipo"),
                        Decla_var = new NonTerminal("Decla_var"),
                        Decla_var_asig = new NonTerminal("Decla_var_asig"),
                        Decla_array = new NonTerminal("Decla_array"),
                        Decla_array_asig = new NonTerminal("Decla_array_asig"),
                        LE = new NonTerminal("LE"),
                        Dims = new NonTerminal("Dims"),
                        Asignacion = new NonTerminal("Asignacion"),
                        AsigSimplificada = new NonTerminal("AsigSimplificada"),
                        Spista = new NonTerminal("Spista"),
                        coment = new NonTerminal("coment"),
                        Valor = new NonTerminal("Valor"),
                        Sent = new NonTerminal("Sent"),
                        LER = new NonTerminal("LER"),
                        Decla_metodos = new NonTerminal("Decla_metodos"),
                        Opr = new NonTerminal("Opr"),
                        E = new NonTerminal("E"),
                        LS = new NonTerminal("LS"),
                        doWhile_ = new NonTerminal("doWhile_"),
                        While_ = new NonTerminal("While_"),
                        For_ = new NonTerminal("For_"),
                        Fun = new NonTerminal("Fun"),
                        LDP = new NonTerminal("LDP"),
                        Switch_ = new NonTerminal("Switch_"),
                        Case_ = new NonTerminal("Case_"),
                        To = new NonTerminal("To"),
                        LCase = new NonTerminal("LCase"),
                        If_ = new NonTerminal("If_"),
                        LID = new NonTerminal("Lista_id");
            RegisterOperators(0, "=", "+=", "-=");
            RegisterOperators(1, Associativity.Left, "||", "&|", "!||");
            RegisterOperators(2, Associativity.Left, "&&", "!&&");
            RegisterOperators(3, Associativity.Right, "!");
            RegisterOperators(4, "==", "!=", ">", "<", ">=", "<=");
            RegisterOperators(5, "+", "-");
            RegisterOperators(6, "%", "/", "*");
            RegisterOperators(7, "^");
            RegisterOperators(8, "++", "--");
            RegisterBracePair("(", ")");
            RegisterBracePair("[", "]");
            RegisterBracePair("{", "}");
            MarkPunctuation(",", "(", ")", "[", "]","{","}");
            MarkPunctuation(Eos);
            S.Rule = P;
            P.Rule = NPista + Indent + CPista + Dedent;
            //ya
            NPista.Rule = "Pista" + id + "extiende" + LID + Eos
                    | "Pista" + id + Eos;
            //ya
            CPista.Rule = CPista + Spista
                     | Spista;
            //ya
            Tipo.Rule = ToTerm("entero")
                    | "cadena"
                    | "boolean"
                    | "doble"
                    | "caracter";
            //ya
            Spista.Rule = Decla_var + Eos
                    | Decla_var_asig + Eos
                    | Asignacion + Eos
                    | Decla_metodos
                    | Decla_array+Eos
                    | Decla_array_asig+Eos;
            //ya
            Decla_metodos.Rule = ToTerm("Keep") + Tipo + id + Lpar + LDP + Rpar + Eos + Indent + LS + Dedent
                                | ToTerm("Keep") + Tipo + id + Lpar + Rpar + Eos + Indent + LS + Dedent
                                | Tipo + id + Lpar + LDP + Rpar + Eos + Indent + LS + Dedent
                                | Tipo + id + Lpar + Rpar + Eos + Indent + LS + Dedent
                                | ToTerm("Keep") + id + Lpar + LDP + Rpar + Eos + Indent + LS + Dedent
                                | ToTerm("Keep") + id + Lpar + Rpar + Eos + Indent + LS + Dedent
                                | id + Lpar + LDP + Rpar + Eos + Indent + LS + Dedent
                                | id + Lpar + Rpar + Eos + Indent + LS + Dedent
                                | ToTerm("Principal") + Lpar + Rpar + Eos + Indent + LS + Dedent;
            //ya
            Decla_var.Rule = Decla_var + "," + id
                      | ToTerm("Keep") + ToTerm("var") + Tipo + id
                      | "var" + Tipo + id
                      | ToTerm("Keep") + ToTerm("var") + Tipo +ToTerm("array")+ id
                      | "var" + Tipo + ToTerm("array") + id;
            //ya
            LID.Rule = LID + "," + id
                | id
                ;
            //ya
            Decla_var_asig.Rule = Decla_var + "=" + Valor;
            //ya
            Decla_array.Rule = Decla_var + Dims;
            //ya
            Decla_array_asig.Rule = Decla_array + "=" + LE;
            //ya
            LE.Rule = LE + "," + E
                | LE + "," + "{" + LE + "}"
                | "{" + LE + "}"
                | E;
            //ya
            Dims.Rule = Dims + ToTerm("[") + E + ToTerm("]")
                    | ToTerm("[") + E + ToTerm("]");
            //ya
            Asignacion.Rule = id + ToTerm("=") + Valor
            | id + Dims + ToTerm("=") + Valor
            | id + ToTerm("+=") + Valor
            | AsigSimplificada;
            //ya
            AsigSimplificada.Rule = id + "++"
            | id + "--"
            | "--" + id
            | "++" + id;
            //ya
            CallMorF.Rule = id + Lpar + Param + Rpar
                       | id + Lpar + Rpar
                       | Fun ;
            //ya
            Param.Rule = Param + ToTerm(",") + Valor
                        | Valor;
            //ya
            Opr.Rule = ToTerm("==")
            | "<"
            | ">"
            | ">="
            | "<="
            | "!=";
            //ya
            Valor.Rule = E + Opr + E
            | Valor + "||" + Valor
            | Valor + "!||" + Valor
            | Valor + "&|" + Valor
            | Valor + "&&" + Valor
            | Valor + "!&&" + Valor
            | "!" + Valor
            | E;
            //ya
            E.Rule = E + "+" + E
                | E + "-" + E
                | E + "*" + E
                | E + "/" + E
                | E + "%" + E
                | E + "^" + E
                | num
                | cad
                | id
                | "falso"
                | "verdadero"
                | caracter
                | CallMorF
                | "(" + Valor + ")"
                | id + Dims
                | AsigSimplificada
                | "!¡" + id;
                ;
            //ya
            Sent.Rule = doWhile_
            | Asignacion + Eos
            | ToTerm("retorna") + Valor + Eos
            | If_
            | Switch_
            | For_
            | While_
            | Decla_var + Eos
            | Decla_var_asig + Eos
            | Decla_array_asig + Eos
            | Decla_array + Eos
            | CallMorF + Eos
            | "salir" + Eos;

            NonGrammarTerminals.Add(ToTerm(@"\"));
            //ya
            If_.Rule = "si" + Lpar + Valor + Rpar + Eos + Indent + LS + Dedent
                    | "si" + Lpar + Valor + Rpar + Eos + Indent + LS + Dedent + "sino" + Eos + Indent + LS + Dedent;
            //ya
            Case_.Rule = "case" + Valor + Eos + Indent + LS + Dedent;
            //ya
            LCase.Rule = LCase + Case_
            | Case_;
            //ya
            Switch_.Rule = "switch" + Lpar + E + Rpar + Eos + Indent + LCase + "default" + Indent + LS + Dedent + Dedent
                        | "switch" + Lpar + E + Rpar + Eos + Indent + LCase + Dedent;
            //ya
            For_.Rule = "para" + Lpar + Asignacion + ";" + Valor + ";" + AsigSimplificada + Rpar + Eos + Indent + LS + Dedent;
            //ya
            While_.Rule = "mientras" + Lpar + Valor + Rpar + Eos + Indent + LS + Dedent;
            //ya
            LS.Rule = LS + Sent
                | Sent;
            //ya
            doWhile_.Rule = "hacer" + Indent + LS + Dedent + "mientras" + Lpar + Valor + Rpar;
            //ya
            LDP.Rule = LDP + "," + Tipo + id
                 | Tipo + id;

            Fun.Rule = "Reproducir" + Lpar + NM + "," + E + "," + E + "," + E + Rpar
                    | "Esperar" + Lpar + E + "," + E + Rpar
                // | "principal" + Lpar + Rpar + LS
                    | "Ordenar" + Lpar + id + "," + To + Rpar
                    | ToTerm("Sumarizar") + Lpar + E + Rpar
                    | "Longitud" + Lpar + E + Rpar
                    | "Mensaje" + Lpar + E + Rpar;
            //ya
            NM.Rule = ToTerm("Do")
                    | "Do#"
                    | "Re"
                    | "Re#"
                    | "Mi"
                    | "Fa"
                    | "Fa#"
                    | "Sol"
                    | "Sol#"
                    | "La"
                    | "La#"
                    | "Si";
            //ya
            To.Rule = ToTerm("ascendente")
                | "descendente"
                | "impares"
                | "pares"
                | "primos";

            this.Root = S;


        }

        public override void CreateTokenFilters(LanguageData language, TokenFilterList filters)
        {
            var outlineFilter = new CodeOutlineFilter(language.GrammarData,
              OutlineOptions.ProduceIndents | OutlineOptions.CheckBraces, ToTerm(@"\")); // "\" is continuation symbol
            filters.Add(outlineFilter);
        }

    }
}